Wireshark分析验证TCP协议
PS:任何技能的养成都需要刻意练习,此外就是十年如一日的坚持。
TCP协议的数据格式
TCP如何建立连接
TCP如何断开连接
TCP状态变迁图
Wireshark分析验证
为什么SYN和FIN会占一个序列号
TCP的数据格式
源端口(Source Port):数据发送方的端口; 目的端口(Destination Port):数据接收方的端口;
序列号(Sequenece number):16 位占 4 个字节,用来标识从 TCP 发端到 TCP 收端发送的数据字节流,其值是该报文段第一个数据字节的数据编号,这个序列号号是 32 位的无符号数,序列号到达 2^32 -1 则又从 0 开始;
确认号(Acknowledgment number):16 位占 4 个字节,指的是期待接收的数据字节的数据编号,也就是上次报文段最后一个数据字节编号加 1 的值;
SYN:标志位,同步序号用来发起一个 TCP 连接,置
SYN = 1
;ACK:标志位,确认序号有效,置
ACK = 1
;RST:标志位,重建连接,置
RST = 1
;FIN:标志位,发端完成发送任务,希望断开连接,置
FIN = 1
;URG:标志位,紧急指针有效,置
URG = 1
;PSH:标志位,接收方应该尽快把这个数据交个应用层,置
PSH = 1。
TCP如何建立连接
客户端请求连接时发送一个报文段
seq = x
,置标志位SYN = 1
, 向服务端发起一个 TCP 连接,服务端根据SYN = 1
知道客户端在请求建立连接;服务端收到后会向客户端请求确认,随后发送一个报文段
seq = y
, 置标志位ACK = 1
、SYN = 1
,将确认序号 ack 设置为客户端的序列号加 1 ,即ack = x + 1
;客户端收到服务端后确定 ack 是否是客户端上一次发的报文段的序列号加 1,即满足
ack = x + 1
,正确则向服务端发送一个报文段seq = x + 1
,置标志位ack = y + 1
,服务端收到后该客户端和服务端的 TCP 连接就建立了,可以互相通信了。
[SYN]
包请求建立连接,然后等待对应主机发送 ACK
应答这次请求,整个过程两次请求连接、两次应答对方请求,谁都正确应答则成功建立链接,其中第二次握手的时候可以拆分为两个过程:服务端发送
ACK
报文段应答客户端的请求;服务端发送
SYN
报文段向客户端请求建立连接。
ack = seq + 1
。TCP如何断开连接
FIN = 1
的报文段给服务端,此时客户端没有了数据发送能力,但是还有接收服务端数据的能力,直到服务端应答一个标志位 FIN = 1
的报文段给客户端,至此 TCP 断开连接。此外为保证断开连接标志位 FIN 占一个序列号,会在后文进一步分析。客户端完成发送任务后,向服务端发送一个报文段
seq = m
,置标志位FIN = 1
,确认序列号 ack 设置为服务端发送的上一个报文段的序列号加 1,告诉服务端要断开连接;服务端收到客户端要断开连接的报文段之后,向客户端应答一个报文段
seq = n
,置标志位ACK = 1
,将确认序号 ack 设置为客户端发送的上一个报文段的序列号加 1 ,即ack = m + 1
,客户端正确收到该报文段就单向断开了与服务段的连接,进入半关闭状态,也就是只能接收服务端的数据,不能向服务端发送数据了;服务端完成发送任务后,向客户端发送一个报文段
seq = n + 1
,置标志位FIN = 1
,确认序列号 ack 设置为客户端发送的上一个报文段的序列号加 1,即ack = m + 1
,告诉客户端要断开连接;客户端收到服务端要断开连接的报文段之后,向服务端应答一个报文段
seq = m + 1
,置标志位ACK = 1
,将确认序号 ack 设置为服务端发送的上一个报文段的序列号加 1 ,即ack = n + 1
,服务端正确收到该报文段就断开了与客户端的连接,此时客户端和服务端就彻底断开了连接。
Wireshark分析验证
TCP状态变迁图
为什么SYN和FIN会占一个序列号
SYN = 1,seq = x
请求建立连接,服务端收到客户端发送的报文段之后要应答客户端的请求,即服务端发送一个报文段 ACK = 1,ack = x + 1
,其中 ACK= 1
表示收到了收到了客户端的连接请求,确认序号 ack = x + 1
表示已经收到序列号为 x 的报文段了,期待收到的下一个报文段的序列号是 x + 1
,显然服务端应答的客户端请求连接的序号为 x 的报文段。AXK = 1,ack = x
,根据确认序列号 ack 的定义 ack = x
表示已经收到已经收到了序列号为 x - 1
的报文段,那么就无法确认客户端请求连接的报文段了,进而 TCP 不能正常完成三次握手,也就无法建立 TCP 连接了。